package jmine.tec.web.wicket.component.picklist;

import java.util.ArrayList;
import java.util.List;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.ListMultipleChoice;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;

/**
 * Componente de Pick List
 * 
 * @author Willian Gigliotti
 * @param <T> tipo de escolha
 */
public class PickList<T> extends Panel {

    private final List<? extends T> choices;

    private List<T> notSelectedChoices;

    private List<T> selectedChoices;

    private ListMultipleChoice<T> notSelectedBox;

    private ListMultipleChoice<T> selectedBox;

    private final IModel<? extends List<T>> model;

    /**
     * Construtor
     * 
     * @param id id da aba
     * @param model model
     * @param choices escolhas
     */
    public PickList(final String id, IModel<? extends List<T>> model, final List<? extends T> choices) {
        super(id);
        this.choices = choices;
        this.model = model;
        this.initComponents();
    }

    /**
     * Altera o label acima da caixa de opções não selecionadas
     * 
     * @param label label to set
     */
    public void setNotSelectedBoxLabel(String label) {
        this.addOrReplace(new Label("notSelectedLabel", label));
    }

    /**
     * Altera o label acima da caixa de opções já selecionadas
     * 
     * @param label label to set
     */
    public void setSelectedBoxLabel(String label) {
        this.addOrReplace(new Label("selectedLabel", label));
    }

    /**
     * Ação para o botão que adiciona todos
     * 
     * @param target target
     * @param formulario form
     */
    private void buttonAddAll(AjaxRequestTarget target, Form formulario) {
        this.clearAll();
        this.selectedChoices.addAll(PickList.this.choices);
        this.refreshChoices(target);
    }

    /**
     * Ação para o botão de remover todos
     * 
     * @param target target
     * @param formulario form
     */
    private void buttonRemoveAll(AjaxRequestTarget target, Form formulario) {
        this.clearAll();
        this.notSelectedChoices.addAll(this.choices);
        this.refreshChoices(target);
    }

    /**
     * Ação para o botão adicionar
     * 
     * @param target target
     * @param formulario form
     */
    private void buttonAdd(AjaxRequestTarget target, Form formulario) {
        this.selectedChoices.addAll(this.notSelectedBox.getModel().getObject());
        this.notSelectedChoices.removeAll(this.notSelectedBox.getModel().getObject());
        this.notSelectedBox.getModel().getObject().clear();
        this.refreshChoices(target);
    }

    /**
     * Botão para o botão de remover
     * 
     * @param target target
     * @param formulario form
     */
    private void buttonRemove(AjaxRequestTarget target, Form formulario) {
        this.notSelectedChoices.addAll(this.selectedBox.getModel().getObject());
        this.selectedChoices.removeAll(this.selectedBox.getModel().getObject());
        this.selectedBox.getModel().getObject().clear();
        this.refreshChoices(target);
    }

    /**
     * Faz a atualização dos choices e coloca os componentes no target
     * 
     * @param target target
     */
    private void refreshChoices(AjaxRequestTarget target) {
        this.notSelectedBox.setChoices(this.notSelectedChoices);
        this.selectedBox.setChoices(this.selectedChoices);

        target.addComponent(this.notSelectedBox);
        target.addComponent(this.selectedBox);
    }

    /**
     * Limpa todas as listas de escolhas e models
     */
    private void clearAll() {
        this.notSelectedChoices.clear();
        this.notSelectedBox.getModel().getObject().clear();
        this.selectedChoices.clear();
        this.selectedBox.getModel().getObject().clear();
    }

    /**
     * Inicializa componentes
     */
    private void initComponents() {
        this.notSelectedChoices = new ArrayList<T>(this.choices);
        this.notSelectedChoices.removeAll(this.model.getObject());
        this.selectedChoices = this.model.getObject();

        this.addOrReplace(new Label("notSelectedLabel", "Opções Disponíveis"));
        this.addOrReplace(new Label("selectedLabel", "Opções Selecionadas"));

        this.initMultipleChoices();
        this.initButtons();
    }

    /**
     * Inicializa as caixas de multipla escolha
     */
    private void initMultipleChoices() {
        this.notSelectedBox = new ListMultipleChoice<T>("regras", new Model<ArrayList<T>>(new ArrayList<T>()), this.notSelectedChoices);
        this.notSelectedBox.setOutputMarkupId(true);
        this.add(this.notSelectedBox);

        this.selectedBox =
                new ListMultipleChoice<T>("regrasSelecionadas", new Model<ArrayList<T>>(new ArrayList<T>()), this.selectedChoices);
        this.selectedBox.setOutputMarkupId(true);
        this.add(this.selectedBox);
    }

    /**
     * Inicializa os botões ( Adicionar, Adicionar Todos, Remover, Remover Todos )
     */
    private void initButtons() {
        this.add(new AjaxButton("btnAdicionar") {
            @Override
            public void onSubmit(AjaxRequestTarget target, Form formulario) {
                PickList.this.buttonAdd(target, formulario);
            }
        });

        this.add(new AjaxButton("btnRemover") {
            @Override
            public void onSubmit(AjaxRequestTarget target, Form formulario) {
                PickList.this.buttonRemove(target, formulario);
            }
        });

        this.add(new AjaxButton("btnAdicionarAll") {
            @Override
            public void onSubmit(AjaxRequestTarget target, Form formulario) {
                PickList.this.buttonAddAll(target, formulario);
            }
        });

        this.add(new AjaxButton("btnRemoverAll") {
            @Override
            public void onSubmit(AjaxRequestTarget target, Form formulario) {
                PickList.this.buttonRemoveAll(target, formulario);
            }
        });
    }

    /**
     * Obtém o valor do campo notSelectedChoices.
     * 
     * @return O valor do campo notSelectedChoices
     */
    public List<T> getNotSelectedChoices() {
        return this.notSelectedChoices;
    }

    /**
     * Obtém o valor do campo selectedChoices.
     * 
     * @return O valor do campo selectedChoices
     */
    public List<T> getSelectedChoices() {
        return this.selectedChoices;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void onBeforeRender() {
        this.notSelectedChoices.removeAll(this.selectedChoices);
        super.onBeforeRender();
    }
}
